/*
** var.hh
** Login : <David@sandrock.lrde.epita.fr>
** Started on  Mon Apr  7 13:41:39 2003 David Lesage
** $Id: var.hh 52 2003-05-19 08:14:55Z burrus_n $
** 
** Copyright (C) 2003 David Lesage
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef   	VAR_HH_
# define   	VAR_HH_

# include <map>

# include "initializer.hh"
# include "varfactory.hh"

namespace evz
{

  /*----.
  | Var |
  `----*/

  //! Represent a variable.
  /*!  
    A variable consist of a number of possible realisations
    (values). Internally, values for a variable are represented by
    sorted integers between 0 and (number of values - 1).

    A hash table allows the user to specifiy values of type T instead
    of unsigned values.

    Each variable defined on the same VarFactory is assigned a unique
    rank to create an order between Vars.
  */

  template<class T>
  class Var
  {
  private:
    friend class VarFactory<T>;

  private:
    typedef Initializer<T> initializer_type;
    typedef std::map<unsigned, T> map_type;
    typedef std::map<T, unsigned> rev_map_type;

  public:

    // Number of realisations
    unsigned size() const
    {
      return real_.size();
    }

    // Add a list of realisations
    void add_reals(const initializer_type& reals)
    {
      for (typename initializer_type::const_iterator real = reals.begin();
	   real != reals.end();
	   ++real)
	add_real(*real);
    }

    // Add a list of realisations from an initializer
    void add_reals(const std::list<T>& reals)
    {
      for (typename std::list<T>::const_iterator real = reals.begin();
	   real != reals.end();
	   ++real)
	add_real(*real);
    }

    // Return a starter for the list of realisations.
    static initializer_type start()
    {
      return initializer_type();
    }

    // Add a new realisation
    void add_real(const T& r)
    {
      assert(real_rev_.find(r) == real_rev_.end());

      unsigned old_size = real_.size();

      real_[old_size] = r;
      real_rev_[r] = old_size;
    }

    // Return the rank of a variable
    unsigned get_rank(void) const
    {
      return rank_;
    }

    // Return the realisation associated to the id u.
    const T& get_real(unsigned u) const
    {
      typename map_type::const_iterator i = real_.find(u);
      assert (i != real_.end());

      return (*i).second;
    }

    // Return the unsigned id associated to a realisation.
    unsigned get_real_id(const T& r) const
    {
      typename rev_map_type::const_iterator i = real_rev_.find(r);
      assert (i != real_rev_.end());

      return (*i).second;
    }

    // Tell if the Var has a particular realisation
    bool has_real(const T& r) const
    {
      typename rev_map_type::const_iterator i = real_rev_.find(r);
      return i != real_rev_.end();
    }

    bool operator==(const Var<T>& v) const
    {
      return v.rank_ == rank_;
    } 

    bool operator!=(const Var<T>& v) const
    {
      return v.rank_ != rank_;
    } 

    bool operator<(const Var<T>& v) const
    {
      return rank_ < v.rank_;
    }

    bool operator>(const Var<T>& v) const
    {
      return rank_ > v.rank_;
    } 

  private:
    Var();

    // This constructor should only be used by a VarFactory.
    Var(unsigned rank) : rank_(rank)
    {}
    
  private:
    map_type real_;
    rev_map_type real_rev_;
    unsigned rank_;
  };

  template<class T>
  inline std::ostream&
  operator<<(std::ostream& o, const Var<T>& v)
  {
    o << "{ ";
    for (unsigned cpt = 0; cpt < v.size(); ++cpt)
      {
	o << v.get_real(cpt);
	if (cpt < v.size() - 1)
	  o << ", ";
      }
    o << " }";
    return o;
  }

} // end of evz

#endif	    /* !VAR_HH_ */
